Skip to content

feat(relay): GroupMind Local — offline LAN coordination relay (MVP)#37

Merged
ThinkOffApp merged 1 commit into
mainfrom
feat/local-relay-mvp
Jul 15, 2026
Merged

feat(relay): GroupMind Local — offline LAN coordination relay (MVP)#37
ThinkOffApp merged 1 commit into
mainfrom
feat/local-relay-mvp

Conversation

@ThinkOffApp

Copy link
Copy Markdown
Owner

What

GroupMind Local — IAK's offline coordination layer. A small always-on relay (runs on the always-on Mac mini) that speaks the subset of GroupMind's message API the fleet uses, so agents fail over to it and keep coordinating with zero internet. Paired with per-machine on-device LLMs (Ollama), it makes a fleet that reasons and coordinates fully offline.

Why

Petrus's ask: mm/mb/phone in a room together with no internet. Today everything routes through cloud GroupMind (Vercel), so an ISP outage silences the whole fleet even though the machines are on the same LAN.

Scope (MVP — this PR)

  • Relay server (scripts/local-relay.mjs, zero-dep): GET /health, POST /api/v1/messages, POST /api/v1/rooms/:room/messages, GET /api/v1/rooms/:room/messages (newest-first, GroupMind shape). Optional token auth (IAK_RELAY_TOKEN). JSONL store.
  • npm run relay + docs/groupmind-local.md.
  • 8 tests (round-trip, both POST forms, room filter, limit ordering, 400s, token auth, 404). Full suite 150 green.
  • Every message carries a UUID + origin:"local-relay" for future sync.

Deliberately NOT in this PR (next)

  1. Client failover — the IAK room client trying cloud, then local, automatically.
  2. Sync-on-reconnect — merge offline history back to cloud GroupMind, deduped by id.

Cross-review welcome @codexmb / @claudemb — especially the ordering (I use JSONL append order, not ms timestamps, so same-millisecond messages stay deterministic) and the auth / fail-open paths.

🤖 Generated with Claude Code

The fleet coordinates through cloud GroupMind (Vercel); internet down = no hub
even when the machines share a LAN. GroupMind Local is a small always-on service
(runs on the always-on Mac mini) speaking the subset of GroupMind's message API
the fleet uses, so agents fail over to it and keep talking with zero internet.
Pairs with per-machine on-device LLMs for a fully offline fleet.

MVP scope: LAN message store + serve (POST/GET /api/v1[/rooms/:room]/messages,
health, optional token auth, JSONL store, zero deps). Every message carries a
UUID + origin:"local-relay" so the next PR can sync offline history to cloud
GroupMind deduped. 8 tests; full suite 150 green.

Follow-ups: client failover (room client tries cloud then local), sync-on-reconnect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@ThinkOffApp
ThinkOffApp merged commit 85ac12d into main Jul 15, 2026
3 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 992f84bbdf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/local-relay.mjs
const chunks = [];
req.on('data', (c) => {
size += c.length;
if (size > MAX_BODY_BYTES) { reject(new Error('payload too large')); req.destroy(); return; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return the 413 instead of resetting oversized posts

When a client posts a message above MAX_BODY_BYTES, this branch destroys the request socket before the outer catch can write the intended 413 JSON response. In that scenario clients see a connection reset/fetch failure instead of { "error": "payload too large" }, so an oversized agent message can look like the relay went down rather than a handled validation error; stop reading or drain the request while still allowing the 413 response to be sent.

Useful? React with 👍 / 👎.

ThinkOffApp added a commit that referenced this pull request Jul 15, 2026
Addresses codex's two P2 findings on #38:
- When both are present, 'after' (seq) is now authoritative and 'since'
  (millisecond created_at) is ignored, so a same-ms checkpoint can't re-drop
  the messages the cursor must return.
- seq is now the 1-based append position, assigned on read, so rows written by
  the #37 MVP (no seq field) get a correct cursor too — after=0 no longer omits
  pre-upgrade offline history.

+2 regression tests. Full suite 154 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant